package com.ashlikun.zxing.analyze

import com.ashlikun.camera.scan.util.CameraXLogUtils
import com.ashlikun.camera.scan.util.CameraXUtils
import com.ashlikun.zxing.DecodeConfig
import com.ashlikun.zxing.reader.MultiFormatReader2
import com.google.zxing.BinaryBitmap
import com.google.zxing.DecodeHintType
import com.google.zxing.LuminanceSource
import com.google.zxing.PlanarYUVLuminanceSource
import com.google.zxing.Result
import com.google.zxing.common.GlobalHistogramBinarizer
import com.google.zxing.common.HybridBinarizer
import com.google.zxing.multi.GenericMultipleBarcodeReader
import com.google.zxing.multi.MultipleBarcodeReader

/**
 * 多格式分析器：主要用于分析识别条形码/二维码
 */
class MultiFormatAnalyzer constructor(config: DecodeConfig = DecodeConfig()) : AreaRectAnalyzer(config) {
    var mReader: MultiFormatReader2? = null
    var mMultipleReader: MultipleBarcodeReader? = null

    init {
        initReader()
    }

    private fun initReader() {
        mReader = MultiFormatReader2()
        mReader!!.setHints(mHints)
        if (isMultipleCode) {
            mMultipleReader = GenericMultipleBarcodeReader(mReader)
        }
    }

    override fun analyze(data: ByteArray?, dataWidth: Int, dataHeight: Int, left: Int, top: Int, width: Int, height: Int): Array<Result>? {
        var rawResult: Array<Result>? = null
        try {
            val start = System.currentTimeMillis()
            val source = PlanarYUVLuminanceSource(data, dataWidth, dataHeight, left, top, width, height, false)
            rawResult = decodeInternal(source, isMultiDecode)
            if (CameraXUtils.isEmpty(rawResult) && mDecodeConfig != null) {
                if (mDecodeConfig.isSupportVerticalCode) {
                    val rotatedData = ByteArray(data!!.size)
                    for (y in 0 until dataHeight) {
                        for (x in 0 until dataWidth) {
                            rotatedData[x * dataHeight + dataHeight - y - 1] = data[x + y * dataWidth]
                        }
                    }
                    rawResult = decodeInternal(PlanarYUVLuminanceSource(rotatedData, dataHeight, dataWidth, top, left, height, width, false), mDecodeConfig.isSupportVerticalCodeMultiDecode)
                }
                if (CameraXUtils.isEmpty(rawResult) && mDecodeConfig.isSupportLuminanceInvert) {
                    rawResult = decodeInternal(source.invert(), mDecodeConfig.isSupportLuminanceInvertMultiDecode)
                }
            }
            if (!CameraXUtils.isEmpty(rawResult)) {
                val end = System.currentTimeMillis()
                CameraXLogUtils.d("Found barcode in " + (end - start) + " ms")
            }
        } catch (e: Exception) {
            e.printStackTrace()
        } finally {
            mReader!!.reset()
        }
        return rawResult
    }

    private fun decodeInternal(source: LuminanceSource, isMultiDecode: Boolean): Array<Result>? {
        var result: Array<Result>? = null
        try {
            try {
                if (mMultipleReader != null) {
                    // 采用HybridBinarizer解析
                    result = mMultipleReader!!.decodeMultiple(BinaryBitmap(HybridBinarizer(source)))
                } else {
                    // 采用HybridBinarizer解析
                    val value = mReader!!.decodeWithState(BinaryBitmap(HybridBinarizer(source)))
                    if (value != null) {
                        result = arrayOf(value)
                    }
                }
            } catch (e: Exception) {
//                e.printStackTrace();
            }
            if (isMultiDecode && CameraXUtils.isEmpty(result)) {
                if (mMultipleReader != null) {
                    // 如果没有解析成功，再采用GlobalHistogramBinarizer解析一次
                    result = mMultipleReader!!.decodeMultiple(BinaryBitmap(GlobalHistogramBinarizer(source)))
                } else {
                    // 如果没有解析成功，再采用GlobalHistogramBinarizer解析一次
                    val value = mReader!!.decodeWithState(BinaryBitmap(GlobalHistogramBinarizer(source)))
                    if (value != null) {
                        result = arrayOf(value)
                    }
                }
            }
        } catch (e: Exception) {
//            e.printStackTrace();
        }
        return result
    }
}
